﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Net;
using System.IO;

namespace ArmoryData.Character
{
    public class CharacterInfo
    {
        #region InstanceVariables
        private Uri armoryUrl;
        #endregion

        #region Constants
        const string UrlFormat = "{0}/{1}?n={2}&r={3}";
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the battlegroup of this character.
        /// </summary>
        public string BattleGroup { get; set; }
        /// <summary>
        /// Gets or sets the url of this character.
        /// </summary>
        public Uri CharUrl { get; set; }
        /// <summary>
        /// Gets or sets the class of this character.
        /// </summary>
        public CharacterClass Class { get; set; }
        public FactionSide Faction { get; set; }
        public Gender Gender { get; set; }
        public string GuildName { get; set; }
        public Uri GuildUrl { get; set; }
        public string LastModified { get; set; }
        public int Level { get; set; }
        public string Name { get; set; }
        public Race Race { get; set; }
        public string Realm { get; set; }
        public int Points { get; set; }
        public string Prefix { get; set; }
        public string Suffix { get; set; }
        public ArenaTeamCollection ArenaTeams { get; set; }

        //Character Tab
        public List<TalentSpec> TalentSpecs { get; set; }
        [Obsolete("Blizzard no longer displays buffs")]
        public List<Buff> Buffs { get; set; }
        [Obsolete("Blizzard no longer displays debuffs")]
        public List<Buff> Debuffs { get; set; }
        public Pvp PvpStats { get; set; }
        public List<Skill> Professions { get; set; }
        public CharacterBars CharacterBars { get; set; }
        public BaseStats BaseStats { get; set; }
        public Resistances Resistances { get; set; }
        public Melee MeleeStats { get; set; }
        public Ranged RangedStats { get; set; }
        public Spell SpellStats { get; set; }
        public Defenses DefenseStats { get; set; }
        public List<Item> Items { get; set; }

        //Reputation Tab
        public List<FactionCategory> FactionCategories { get; set; }

        //Skills Tab
        public List<SkillCategory> SkillCategories { get; set; }

        //Achievements
        public List<Achievement> RecentAchievements { get; set; }
        public List<AchievementCategory> AchievementCategories { get; set; }
        public int AchievementsEarned { get; set; }
        public int TotalAchievements { get; set; }
        public int AchievementPoints { get; set; }
        #endregion 

        #region Constructors
        public CharacterInfo(string name, string realm, Uri armoryUrl)
        {
            this.Name = name;
            this.Realm = realm;
            this.armoryUrl = armoryUrl;

            BaseStats = new BaseStats();
            Items = new List<Item>();
            Items.Add(new Item() { Name = "null" });
            TalentSpecs = new List<TalentSpec>();
            PvpStats = new Pvp();
            Professions = new List<Skill>();
            CharacterBars = new CharacterBars();
            Resistances = new Resistances();
            MeleeStats = new Melee();
            RangedStats = new Ranged();
            SpellStats = new Spell();
            DefenseStats = new Defenses();
            ArenaTeams = new ArenaTeamCollection();
            FactionCategories = new List<FactionCategory>();
        }
        #endregion

        #region Methods
        public AchievementCategory GetAchievementCategory(int id)
        {
            foreach (AchievementCategory category in AchievementCategories)
            {
                if (category.Id == id) return category;
            }
            return AchievementCategories[0];
        }

        private XElement GetPageXml(ArmoryPage page)
        {
            Uri url = new Uri(string.Format(UrlFormat, armoryUrl, page, Name, Realm));
            return XElement.Parse(Connector.GetHtml(url));
        }

        public void DownloadItems(bool downloadSockets, string wowheadLocal)
        {
            // Load the XML from the armory
            XElement itemXml = GetPageXml(ArmoryPage.Character);

            // Get list of items from armory
            var itemList = from i in itemXml.Descendants("item")
                           select i;
            foreach (var i in itemList)
            {
                // Download data for item
                Item x = new Item();
                x.Id = i.Attribute("id").Int32Value();
                x.Slot = i.Attribute("slot").Int32Value();                        
                x.Durability = i.Attribute("slot").Int32Value();
                x.Gem0Id = i.Attribute("gem0Id").Int32Value();
                x.Gem1Id = i.Attribute("gem1Id").Int32Value();
                x.Gem2Id = i.Attribute("gem2Id").Int32Value();
                x.Icon = i.Attribute("icon").Value;
                x.MaxDurability = i.Attribute("maxDurability").Int32Value();
                x.PermanentEnchant = i.Attribute("permanentenchant").Int32Value();
                x.RandomProperties = i.Attribute("randomPropertiesId").Int32Value();

                // Add item to list
                Items.Add(x);
            }

            // Reorder the items
            Item[] newItems = new Item[19];
            for (int i = 0; i < Items.Count; i++)
            {
                if (Items[i].Id == 0)
                {
                    // No item in slot
                    Items[i].Id = -1;
                    Items[i].Icon = "-1";
                }

                // Put items in order of slot
                if (Items[i].Slot >= 0 && Items[i].Slot <= 18)
                    newItems[Items[i].Slot] = Items[i];
            }
            
            Items.Clear();
            // Add items back into original list
            foreach (Item itm in newItems)
            {
                Item i = itm;
                if (i == null) i = new Item() { Id = -1, Icon = "-1" };
                Items.Add(i);
            }
               

            // Create a pcs string for item set on wowhead
            string pcs = string.Empty;
            foreach (Item itm in Items)
                pcs += itm.Id + ":";

            // Download Wowhead data
            foreach (Item i in Items)
            {
                // Get Wowhead XML
                itemXml = XElement.Parse(Connector.GetHtml(new Uri(string.Format("http://{1}.wowhead.com/?item={0}&xml", i.Id, wowheadLocal))));
                
                if (itemXml.Descendants("error").Count<XElement>() <= 0) // Error Check
                {
                    i.Name = itemXml.Descendant("name").Value;
                    i.InventorySlot = itemXml.Descendant("inventorySlot").Value;
                    i.Link = itemXml.Descendant("link").Value;
                    i.Quality = itemXml.Descendant("quality").Attribute("id").Int32Value();
                    if (downloadSockets)
                    {
                        // Download power tooltip 
                        string tooltipHtml = Connector.GetHtml(new Uri(string.Format("http://{0}.wowhead.com/?item={1}&ench={2}&gems={3}:{4}:{5}&lvl={6}&pcs={7}&rand={8}&power", wowheadLocal, i.Id, i.PermanentEnchant, i.Gem0Id, i.Gem1Id, i.Gem2Id, Level, pcs, i.RandomProperties)));
                        tooltipHtml = tooltipHtml.Remove(0, tooltipHtml.IndexOf("tooltip"));
                        tooltipHtml = tooltipHtml.Remove(0, tooltipHtml.IndexOf(":") + 3);
                        try
                        {
                            tooltipHtml = tooltipHtml.Remove(tooltipHtml.IndexOf("</table>'"), tooltipHtml.Length - tooltipHtml.IndexOf("</table>'")) + "</table>";
                        }
                        catch (ArgumentOutOfRangeException ex) { ex.ToString(); } // ignore exception
                        tooltipHtml = tooltipHtml.Replace("'\r\n});\r\n", "").Replace("\\'", "'").Replace("onmouse", "notonmouselol");

                        i.HtmlTooltip = tooltipHtml;
                    }
                        // Download normal tooltip
                    else i.HtmlTooltip = itemXml.Descendant("htmlTooltip").Value;
                }
            }
        }

        /// <summary>
        /// Downloads the character info.
        /// </summary>
        /// <exception cref="CharacterNotFoundException">The character no longer exists.</exception>
        public void DownloadCharacterInfo()
        {
            IEnumerable<XElement> dataList;
            XElement charData;
            XElement data;

            // Load the XML from the armory
            XElement charXml = GetPageXml(ArmoryPage.Character);

            //Error Check
            if (charXml.Element("characterInfo").Attribute("errCode") != null)
                throw new CharacterNotFoundException();
            // Get character element
            dataList = from i in charXml.Descendants("character")
                           where i.Parent.Name.ToString() == "characterInfo"
                           select i;
            data = dataList.ElementAt<XElement>(0);

            // Download character info
            BattleGroup = data.Attribute("battleGroup").Value;
            Faction = (FactionSide)data.Attribute("factionId").Int32Value();
            GuildName = data.Attribute("guildName").Value;
            Name = data.Attribute("name").Value;
            Race = (Race)data.Attribute("raceId").Int32Value();
            Class = (CharacterClass)data.Attribute("classId").Int32Value();
            Gender = (Gender)data.Attribute("genderId").Int32Value();
            Level = data.Attribute("level").Int32Value();
            Realm = data.Attribute("realm").Value;
            LastModified = data.Attribute("lastModified").Value;
            Points = data.Attribute("points").Int32Value();
            Prefix = data.Attribute("prefix").Value;
            Suffix = data.Attribute("suffix").Value;


            // Get character tab XML
            charData = charXml.Descendant("characterTab");

            /** Talents **/
            foreach (XElement t in charData.Descendant("talentSpecs").Descendants())
            {
                TalentSpec spec = new TalentSpec();
                spec.Active = t.Attribute("active") != null;
                spec.Icon = t.Attribute("icon").Value;
                spec.Name = t.Attribute("prim").Value;
                spec.TreeOne = t.Attribute("treeOne").Int32Value();
                spec.TreeTwo = t.Attribute("treeTwo").Int32Value();
                spec.TreeThree = t.Attribute("treeThree").Int32Value();
                TalentSpecs.Add(spec);
            }

            /** Buffs **/
            // Obselete

            /** Debuffs **/
            // Obselete

            /** PvP **/
            // Get pvp element
            data = charData.Descendant("pvp");

            // Parse pvp element
            PvpStats.LifetimeHonorableKills = data.Descendant("lifetimehonorablekills").Attribute("value").Int32Value();
            PvpStats.ArenaCurrency = data.Descendant("arenacurrency").Attribute("value").Int32Value();

            /** Professions **/
            //Parse profession elements
            foreach (XElement p in charData.Descendant("professions").Descendants())
            {
                Skill s = new Skill();
                s.Key = p.Attribute("key").Value;
                s.Max = p.Attribute("max").Int32Value();
                s.Name = p.Attribute("name").Value;
                s.Value = p.Attribute("value").Int32Value();
                Professions.Add(s);
            }

            // Make sure there are 2 professions
            while (Professions.Count < 2) Professions.Add(new Skill());

            /** Character Bars **/
            // Get bar elements
            dataList = charData.Descendant("characterBars").Descendants();

            // Parse health bar
            data = dataList.ElementAt(0);
            CharacterBars.Health.Effective = data.Attribute("effective").Int32Value();
            
            // Parse second bar
            data = dataList.ElementAt(1);
            CharacterBars.SecondBar.Casting = data.Attribute("casting").Int32Value();
            CharacterBars.SecondBar.NotCasting = data.Attribute("notCasting").Int32Value();
            CharacterBars.SecondBar.Effective = data.Attribute("effective").Int32Value();
            CharacterBars.SecondBar.Type = data.Attribute("type").Value;

            /** Base Stats **/
            // Get base stats element
            dataList = charData.Descendant("baseStats").Descendants();
            
            // Parse base stat elements
            foreach (XAttribute a in dataList.ElementAt(0).Attributes())
                BaseStats.Strength.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(1).Attributes())
                BaseStats.Agility.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(2).Attributes())
                BaseStats.Stamina.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(3).Attributes())
                BaseStats.Intellect.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(4).Attributes())
                BaseStats.Spirit.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(5).Attributes())
                BaseStats.Armor.Add(a.Name.ToString(), a.Value);

            /** Resistances **/
            // Get resistance elements
            dataList = charData.Descendant("resistances").Descendants();

            // Parse resistance elements
            foreach (XAttribute a in dataList.ElementAt(0).Attributes())
                Resistances.Values.Arcane.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(1).Attributes())
                Resistances.Values.Fire.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(2).Attributes())
                Resistances.Values.Frost.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(3).Attributes())
                Resistances.Values.Holy.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(4).Attributes())
                Resistances.Values.Nature.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(5).Attributes())
                Resistances.Values.Shadow.Add(a.Name.ToString(), a.Value);

            /** Melee **/
            // Get melee elements
            dataList = charData.Descendant("melee").Descendants();

            // Parse melee elements
            foreach (XAttribute a in dataList.ElementAt(0).Attributes())
                MeleeStats.MainhandDamage.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(1).Attributes())
                MeleeStats.OffhandDamage.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(2).Attributes())
                MeleeStats.MainhandSpeed.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(3).Attributes())
                MeleeStats.OffhandSpeed.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(4).Attributes())
                MeleeStats.Power.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(5).Attributes())
                MeleeStats.HitRating.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(6).Attributes())
                MeleeStats.CritChance.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(7).Attributes())
                MeleeStats.Expertise.Add(a.Name.ToString(), a.Value);

            /** Ranged **/
            // Get ranged elements
            dataList = charData.Descendant("ranged").Descendants();

            // Parse ranged elements
            foreach (XAttribute a in dataList.ElementAt(0).Attributes())
                RangedStats.WeaponSkill.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(1).Attributes())
                RangedStats.Damage.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(2).Attributes())
                RangedStats.Speed.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(3).Attributes())
                RangedStats.Power.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(4).Attributes())
                RangedStats.HitRating.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(5).Attributes())
                RangedStats.CritChance.Add(a.Name.ToString(), a.Value);

            /** Defenses **/
            // Get defense elements
            dataList = charData.Descendant("defenses").Descendants();

            // Parse defense elements
            foreach (XAttribute a in dataList.ElementAt(0).Attributes())
                DefenseStats.Armor.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(1).Attributes())
                DefenseStats.Defense.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(2).Attributes())
                DefenseStats.Dodge.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(3).Attributes())
                DefenseStats.Parry.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(4).Attributes())
                DefenseStats.Block.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(5).Attributes())
                DefenseStats.Resilience.Add(a.Name.ToString(), a.Value);

            /** Spell **/
            // Bonus Damage
            // Get bonus damage elements
            dataList = charData.Descendant("bonusDamage").Descendants();
            
            // Parse bonus damage elements
            foreach (XAttribute a in dataList.ElementAt(0).Attributes())
                SpellStats.BonusDamage.Arcane.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(1).Attributes())
                SpellStats.BonusDamage.Fire.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(2).Attributes())
                SpellStats.BonusDamage.Frost.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(3).Attributes())
                SpellStats.BonusDamage.Holy.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(4).Attributes())
                SpellStats.BonusDamage.Nature.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(5).Attributes())
                SpellStats.BonusDamage.Shadow.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(6).Attributes())
                SpellStats.BonusDamage.PetBonus.Add(a.Name.ToString(), a.Value);

            // Crit Chance
            // Get crit chance elements
            dataList = charData.Descendants("critChance").ElementAt(2).Descendants();

            // Parse crit chance elements
            foreach (XAttribute a in dataList.ElementAt(0).Attributes())
                SpellStats.CritChance.Arcane.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(1).Attributes())
                SpellStats.CritChance.Fire.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(2).Attributes())
                SpellStats.CritChance.Frost.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(3).Attributes())
                SpellStats.CritChance.Holy.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(4).Attributes())
                SpellStats.CritChance.Nature.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(5).Attributes())
                SpellStats.CritChance.Shadow.Add(a.Name.ToString(), a.Value);


            //Get spell elements
            dataList = charData.Descendant("spell").Descendants();

            // Parse spell elements
            foreach (XAttribute a in dataList.ElementAt(8).Attributes())
                SpellStats.BonusHealing.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(9).Attributes())
                SpellStats.HitRating.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(10).Attributes())
                SpellStats.CritChance.Rating.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(17).Attributes())
                SpellStats.Penetration.Add(a.Name.ToString(), a.Value);
            foreach (XAttribute a in dataList.ElementAt(18).Attributes())
                SpellStats.ManaRegen.Add(a.Name.ToString(), a.Value);
        }

        public void DownloadTalentInfo()
        {
            XElement talentXml = GetPageXml(ArmoryPage.Talent);
            int index = 0;
            foreach (XElement t in talentXml.Descendants("talentGroup"))
            {
                TalentSpecs[index].Url = t.Descendant("talentSpec").Attribute("value").Value;

                // Glyphs
                foreach (XElement s in t.Descendants("glyph"))
                {
                    Glyph g = new Glyph();
                    g.Effect = s.Attribute("effect").Value;
                    g.Icon = s.Attribute("icon").Value;
                    g.Id = s.Attribute("id").Int32Value();
                    g.Name = s.Attribute("name").Value;
                    g.Type = (GlyphType)(Enum.Parse(typeof(GlyphType), s.Attribute("type").Value, true));
                    TalentSpecs[index].Glyphs.Add(g);
                }

                index++;
            }
        }

        public void DownloadArenaTeams()
        {
            XElement arenaXml = GetPageXml(ArmoryPage.ArenaTeams);
            foreach (XElement data in arenaXml.Descendants("arenaTeam"))
            {
                ArenaTeam team = new ArenaTeam();
                team.BattleGroup = data.Attribute("battleGroup").Value;
                team.Faction = data.Attribute("faction").Value;
                team.FactionId = data.Attribute("factionId").Int32Value();
                team.GamesPlayed = data.Attribute("gamesPlayed").Int32Value();
                team.GamesWon = data.Attribute("gamesWon").Int32Value();
                team.LastSeasonRanking = data.Attribute("lastSeasonRanking").Int32Value();
                team.Name = data.Attribute("name").Value;
                team.Ranking = data.Attribute("ranking").Int32Value();
                team.Rating = data.Attribute("rating").Int32Value();
                team.Realm = data.Attribute("realm").Value;
                team.RealmUrl = new Uri(data.Attribute("realmUrl").Value);
                team.SeasonGamesWon = data.Attribute("seasonGamesWon").Int32Value();
                team.SeasonGamesPlayed = data.Attribute("seasonGamesPlayed").Int32Value();
                team.Size = data.Attribute("size").Int32Value();
                foreach (XElement m in data.Descendants("character"))
                {
                    Member member = new Member();
                    member.BattleGroup = m.Attribute("battleGroup").Value;
                    member.CharUrl = new Uri(m.Attribute("charUrl").Value);
                    member.Class = m.Attribute("class").Value;
                    member.ClassId = m.Attribute("classId").Int32Value();
                    member.Contribution = m.Attribute("contribution").Int32Value();
                    member.GamesPlayed = m.Attribute("gamesPlayed").Int32Value();
                    member.GamesWon = m.Attribute("gamesWon").Int32Value();
                    member.Gender = m.Attribute("gender").Value;
                    member.GenderId = m.Attribute("genderId").Int32Value();
                    if (m.Attribute("guild") != null) member.Guild = m.Attribute("guild").Value;
                    member.GuildId = m.Attribute("guildId").Int32Value();
                    member.Name = m.Attribute("name").Value;
                    member.Race = m.Attribute("race").Value;
                    member.RaceId = m.Attribute("raceId").Int32Value();
                    member.SeasonGamesPlayed = m.Attribute("seasonGamesPlayed").Int32Value();
                    member.SeasonGamesWon = m.Attribute("seasonGamesWon").Int32Value();
                    member.TeamRank = m.Attribute("teamRank").Int32Value();

                    team.Members.Add(member);
                }
                ArenaTeams.Add(team);
            }
        }

        public void DownloadAchievements()
        {
            throw new NotImplementedException();
        }
        
        #endregion

        public override string ToString()
        {
            string ret = "";
            ret += Prefix + Name + Suffix + Environment.NewLine;
            ret += string.Format("<{0}>", GuildName) + Environment.NewLine;
            ret += string.Format("Level {0} {1} {2} {3}", Level, Gender, Race, Class);
            return ret;
        }


        public void DownloadReputationTab()
        {
            XElement repXml = GetPageXml(ArmoryPage.Reputation);
            var dataList = from i in repXml.Descendants("faction")
                           where i.Parent.Name == "reputationTab" 
                           select i;

            foreach (XElement e in dataList)
            {
                FactionCategory x = new FactionCategory();
                x.Key = e.Attribute("key").Value;
                x.Name = e.Attribute("name").Value;
                x.Id = e.Attribute("id").Int32Value();

                var children = from i in e.Descendants()
                               where i.Parent == e
                               select i;
                foreach (XElement child in children)
                {
                    Faction f = GetFactionInfo(child);
                    if (f.Header) 
                        foreach (XElement g in child.Descendants())
                            f.Children.Add(GetFactionInfo(g));
                    x.Factions.Add(f);
                }
                FactionCategories.Add(x);
            }
        }

        static Faction GetFactionInfo(XElement child)
        {
            Faction f = new Faction();
            f.Header = child.Attribute("header") != null;
            f.Key = child.Attribute("key").Value;
            f.Name = child.Attribute("name").Value;
            f.Id = child.Attribute("id").Int32Value();

            if (child.Attribute("reputation") != null)
            {
                f.Reputation = child.Attribute("reputation").Int32Value();

                int rep = f.Reputation;
                if (rep >= -42000 && rep <= -6001)
                {
                    f.Rank = FactionRank.Hated;
                    f.RepRange = 36000;
                    f.MaxRep = -6001;
                }
                else if (rep >= -6000 && rep <= -3001)
                {
                    f.Rank = FactionRank.Hostile;
                    f.RepRange = 3000;
                    f.MaxRep = -3001;
                }
                else if (rep >= -3000 && rep <= -1)
                {
                    f.Rank = FactionRank.Unfriendly;
                    f.MaxRep = -1;
                    f.RepRange = 3000;
                }

                else if (rep >= 0 && rep <= 2999)
                {
                    f.Rank = FactionRank.Neutral;
                    f.MaxRep = 2999;
                    f.RepRange = 3000;
                }
                else if (rep >= 3000 && rep <= 8999)
                {
                    f.Rank = FactionRank.Friendly;
                    f.MaxRep = 8999;
                    f.RepRange = 6000;
                }
                else if (rep >= 9000 && rep <= 20999)
                {
                    f.Rank = FactionRank.Honored;
                    f.MaxRep = 20999;
                    f.RepRange = 12000;
                }
                else if (rep >= 21000 && rep <= 41999)
                {
                    f.Rank = FactionRank.Revered;
                    f.MaxRep = 41999;
                    f.RepRange = 21000;
                }
                else if (rep >= 42000 && rep <= 42999)
                {
                    f.Rank = FactionRank.Exalted;
                    f.MaxRep = 42999;
                    f.RepRange = 1000;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("child", "The reputation value does not match any known rank.");
                }
            }
            return f;
        }
    }
}
